/***************************************************************************
 *   Copyright (C) 2009 by Geoffrey McRae   *
 *   geoff@spacevs.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef VIDEO_DIRECTFB

#include "directfb.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <directfb.h>

void mpr_video_directfb_queue_yuv420p(AVFrame *pFrame, void *ptr, unsigned int pitch, unsigned int h);
void mpr_video_directfb_queue_pal8   (AVFrame *pFrame, void *ptr, unsigned int pitch, unsigned int h);

typedef struct {
	IDirectFB		*dfb;
	IDirectFBSurface	*primary;
	unsigned int		pix_fmt;
	unsigned int		pixelformat;
	unsigned int		w, h, a_w, a_h;
	void			(*queue_func)(AVFrame *pFrame, void *ptr, unsigned int pitch, unsigned int h);
} mpr_video_directfb_data_t;

void *mpr_video_directfb_new(void *data) {
	mpr_video_directfb_data_t	*stor;
	int				argc = 0;
	char				**argv;

	stor = calloc(sizeof(mpr_video_directfb_data_t), 1);

	DirectFBInit  (&argc, &argv);
	DirectFBCreate(&stor->dfb);
	stor->dfb->SetCooperativeLevel(stor->dfb, DFSCL_NORMAL);

	return stor;
}

void mpr_video_directfb_free(void *data) {
	mpr_video_directfb_data_t *stor = data;
	free(stor);
}

bool mpr_video_directfb_open(void *data, unsigned int width, unsigned int height, unsigned int actual_width, unsigned int actual_height, unsigned int pix_fmt) {
	mpr_video_directfb_data_t *stor = data;
	DFBSurfaceDescription dsc;

	stor->w 	= width;
	stor->h		= height;
	stor->pix_fmt	= pix_fmt;
	stor->a_w	= actual_width;
	stor->a_h	= actual_height;

	switch(pix_fmt) {
		case PIX_FMT_YUV420P: stor->pixelformat = DSPF_YV12 ; stor->queue_func = mpr_video_directfb_queue_yuv420p; break;
		case PIX_FMT_PAL8   : stor->pixelformat = DSPF_RGB32; stor->queue_func = mpr_video_directfb_queue_pal8   ; break;
		default:
			ERR("%s", "I cant handle this format yet");
			return false;
	}

	dsc.flags	= DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
	dsc.caps	= DSCAPS_PRIMARY;
	dsc.width	= width;
	dsc.height	= height;
	dsc.pixelformat = stor->pixelformat;

	stor->dfb->CreateSurface(stor->dfb, &dsc, &stor->primary);
	stor->primary->SetBlittingFlags(stor->primary, DSBLIT_NOFX);
	return true;
}

void mpr_video_directfb_close(void *data) {
	mpr_video_directfb_data_t *stor = data;

	stor->primary->Release	(stor->primary);
	stor->dfb->Release	(stor->dfb);
}

bool mpr_video_directfb_queue_new(void *data, AVFrame *pFrame, void **storage) {
	mpr_video_directfb_data_t	*stor = data;
	IDirectFBSurface		*suf = NULL;
	DFBSurfaceDescription		dsc;

	dsc.flags	= DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
	dsc.caps	= DSCAPS_SYSTEMONLY;
	dsc.width	= stor->a_w;
	dsc.height	= stor->a_h;
	dsc.pixelformat	= stor->pixelformat;
	stor->dfb->CreateSurface(stor->dfb, &dsc, &suf);
	
	*storage = suf;
	return true;
}

void mpr_video_directfb_queue_free(void *data, AVFrame *pFrame, void **storage) {
	IDirectFBSurface *suf = *storage;
	suf->Release(suf);
}

bool mpr_video_directfb_queue(void *data, AVFrame *pFrame, void **storage) {
	mpr_video_directfb_data_t	*stor = data;
	IDirectFBSurface		*suf = *storage;
	void				*ptr;
	int				pitch;

	suf->Lock(suf, DSLF_WRITE, &ptr, &pitch);
	stor->queue_func(pFrame, ptr, pitch, stor->a_h);
	suf->Unlock(suf);

	return true;
}

bool mpr_video_directfb_display(void *data, void **storage) {
	mpr_video_directfb_data_t	*stor	= data;
	IDirectFBSurface		*suf	= *storage;

	stor->primary->Blit(stor->primary, suf, NULL, 0, 0);
	return true;
}

void mpr_video_directfb_drop(void *data, void **storage) {
	/*
	mpr_video_directfb_data_t	*stor	= data;
	mpr_video_directfb_frame_t	*f	= *storage;
	*/
}

void mpr_video_directfb_queue_yuv420p(AVFrame *pFrame, void *ptr, unsigned int pitch, unsigned int h) {
	void *ptrU, *ptrV;
	unsigned int y;

	for(y = 0; y < h; ++y) {
		memcpy(ptr, &pFrame->data[0][y * pFrame->linesize[0]], pitch);
		ptr += pitch;
	}

	h /= 2;
	pitch /= 2;
	ptrU = ptr;
	ptrV = ptrU + (h * pitch);

	for(y = 0; y < h; ++y) {
		memcpy(ptrU, &pFrame->data[2][y * pFrame->linesize[2]], pitch);
		memcpy(ptrV, &pFrame->data[1][y * pFrame->linesize[1]], pitch);
		ptrU += pitch;
		ptrV += pitch;
	}
}

void mpr_video_directfb_queue_pal8(AVFrame *pFrame, void *ptr, unsigned int pitch, unsigned int h) {
	uint32_t	*palette	= (uint32_t*)pFrame->data[1];
	uint32_t	*pixel		= (uint32_t*)ptr;
	unsigned int	x, y;

	pitch /= sizeof(uint32_t);
	for(y = 0; y < h; ++y)
		for(x = 0; x < pitch; ++x)
			*pixel++ = palette[pFrame->data[0][(y * pFrame->linesize[0]) + x]];
}

#endif